using System;
using System.Collections.Generic;
using System.Text;
using System.CodeDom;
using OpenComposite.Base.Designer;

namespace OpenComposite.EII.CodeGenerators
{
	public class BusinessProcessCodeGenerator
	{
		#region Initialization
		public BusinessProcessCodeGenerator(string codeNamespace)
		{
			if ( !string.IsNullOrEmpty(codeNamespace) )
				_codeNamespace = codeNamespace;

			init();
		}
		private void init()
		{

		}
		#endregion

		#region Public Members

		#region Methods
		public void GenerateBusinessProcessCSCode(
			Designer.BusinessProcess.StartSymbol processstart,
			string projectpath, string projectname)
		{
			// TODO: generate activity classes

			// TODO: generate rule class

			// TODO: generate mapping class

			// TODO: generate service class

			// TODO: generate process class

			// TODO: create vs.net project

			// TODO: generate code files

			// TODO: compile
		}
		#endregion

		#endregion

		#region Private Members

		#region Variables
		private string _codeNamespace = "OpenComposite.Generated";
		private string _classProcessNm = "Process";
		private string _classActivitiesNm = "Activities";
		//private string _classRulesNm = "Rules";
		//private string _classMappingsNm = "Mappings";
		//private string _classServicesNm = "Services";

		private string _methodProcMainNm = "ProcessMain";

		private string _methodPrefixActCancel = "Cancel_";
		private string _methodPrefixActCompensate = "Compensate_";

		//private List<Designer.BusinessProcess.ActivitySymbol> _activities;
		#endregion

		#region Methods
		private CodeCompileUnit createActivitiesClass(
			Designer.BusinessProcess.StartSymbol processstart)
		{
			CodeCompileUnit codeActivitiesClass = new CodeCompileUnit();

			// create namespace
			CodeNamespace nsActs = new CodeNamespace(_codeNamespace);
			codeActivitiesClass.Namespaces.Add(nsActs);

			// create activites class
			CodeTypeDeclaration classActs = new CodeTypeDeclaration(_classActivitiesNm);
			classActs.IsClass = true;
			classActs.Attributes = MemberAttributes.Public | MemberAttributes.Final;

			nsActs.Types.Add(classActs);

			int i = 0;
			List<DesignerControl> ctrls = new List<DesignerControl>();
			ctrls.Add(processstart);

			// for each process activity
			while ( ctrls.Count > i ) {
				// if current control is a process activity
				if ( ctrls[i] is Designer.BusinessProcess.ActivitySymbol ) {
					// add members for current activity
					addMembersForActivity((Designer.BusinessProcess.ActivitySymbol)ctrls[i], ref classActs);
				}

				// add successors of current control to list
				DesignerControl[] successors = ctrls[i].GetSuccessors();
				foreach ( DesignerControl dc in successors ) {
					// if not in list then add to list
					if ( !ctrls.Contains(dc) )
						ctrls.Add(dc);
				}

				i++;
			}
			return codeActivitiesClass;
		}
		private void addMembersForActivity(
			Designer.BusinessProcess.ActivitySymbol activity,
			ref CodeTypeDeclaration codeActivitiesClass)
		{
			// create region for activity
			CodeRegionDirective regionStart = new CodeRegionDirective(CodeRegionMode.Start, activity.Text);
			CodeRegionDirective regionEnd = new CodeRegionDirective(CodeRegionMode.End, activity.Text);

			// add main activity method
			CodeMemberMethod methodMain = new CodeMemberMethod();
			methodMain.Name = activity.Name;
			methodMain.Attributes = MemberAttributes.Public | MemberAttributes.Final;
			methodMain.StartDirectives.Add(regionStart);

			// TODO: add method code

			// add cancel method
			CodeMemberMethod methodCancel = new CodeMemberMethod();
			methodCancel.Name = string.Join("", new string[] { _methodPrefixActCancel, activity.Name });
			methodCancel.Attributes = MemberAttributes.Public | MemberAttributes.Final;

			// TODO: add cancel method code

			// add compensate method
			CodeMemberMethod methodCompensate = new CodeMemberMethod();
			methodCompensate.Name = string.Join("", new string[] { _methodPrefixActCompensate, activity.Name });
			methodCompensate.Attributes = MemberAttributes.Public | MemberAttributes.Final;
			methodCompensate.EndDirectives.Add(regionEnd);

			// TODO: add compensate methods code

			// add methods to activities class
			codeActivitiesClass.Members.Add(methodMain);
			codeActivitiesClass.Members.Add(methodCancel);
			codeActivitiesClass.Members.Add(methodCompensate);
		}

		private CodeCompileUnit createRuleClass(
			List<Repository.RepositoryBusinessRule> rules)
		{
			CodeCompileUnit codeRuleClass = new CodeCompileUnit();

			// TODO: for each rule in rules

				// TODO: add rule method to rule class

			return codeRuleClass;
		}

		private CodeCompileUnit createMappingClass(
			List<Designer.BusinessProcess.ActivitySymbol> listActivities,
			string projectpath)
		{
			CodeCompileUnit codeMappingClass = new CodeCompileUnit();

			// TODO: create mepping class

			// TODO: for each activity

				// TODO: save input / output XSLT file

				// TODO: create method for input mapping

				// TODO: create method for output mapping

			return codeMappingClass;
		}

		private CodeCompileUnit createServiceClass(
			List<object/* TODO: physical EP */> listPhysicalEPs)
		{
			CodeCompileUnit codeServices = new CodeCompileUnit();

			// TODO: create services class

			// TODO: for each physical endpoint (=>web service operation)

				// TODO: create invoke method

				// TODO: create begin invoke method

				// TODO: create end invoke method

			return codeServices;
		}

		private CodeCompileUnit createProcessClass(
			Designer.BusinessProcess.StartSymbol processstart)
		{
			CodeCompileUnit codeProcess = new CodeCompileUnit();

			// create namespace for process class
			CodeNamespace procns = new CodeNamespace(_codeNamespace);

			// create process class
			CodeTypeDeclaration classProc = new CodeTypeDeclaration(_classProcessNm);
			classProc.IsClass = true;
			classProc.Attributes = MemberAttributes.Public | MemberAttributes.Final;

			procns.Types.Add(classProc);

			// create process main method
			CodeMemberMethod methodProcMain = new CodeMemberMethod();
			methodProcMain.Name = _methodProcMainNm;

			classProc.Members.Add(methodProcMain);

			// TODO: create instances of activities

			// TODO: recursive add code for next activities

			return codeProcess;
		}
		private void addActivityCode(DesignerControl ctrl, CodeMemberMethod methodProcMain)
		{
			// TODO: switch designer control type
			if ( ctrl is Designer.BusinessProcess.ActivitySymbol ) {
				// TODO: add invocation of activity
			} else if ( ctrl is Designer.Generic.ANDSymbol ) {
				// TODO: add parallel activity invocation
			} else if ( ctrl is Designer.Generic.ORSymbol ) {
				// TODO: add rules based activity invocation of type OR
			} else if ( ctrl is Designer.Generic.XORSymbol ) {
				// TODO: add rules based activity invocation of type XOR
			} 
		}
		private void addActivityInvoke(Designer.BusinessProcess.ActivitySymbol activity)
		{
			// TODO: add code for activity invoke
		}
		private void addParallelActivityInvoke(Designer.Generic.ANDSymbol and)
		{
			// TODO: add parallel activity invoke
		}
		private void addRuleBaseActivityInvoke(Designer.Generic.ORSymbol or)
		{
			// TODO: for each next activity

				// TODO: add IF ( rule )

				// TODO: invoke activity
		}
		private void addRuleBaseActivityInvoke(Designer.Generic.XORSymbol xor)
		{
			// TODO: for each next activity

				// TODO: add IF ( rule )

				// TODO: invoke activity
		}
		#endregion

		#endregion

	}
}
